package tg1;

import java.net.*;
import java.util.*;

import tg1.JdbcDAO;
import tg1.TrackerHttpUtils;
import tg1.TrackerProperties;

 
 public class RequestHandler {
 
	private static final String OK = "OK";
	
	private static JdbcDAO JdbcDAO; 
	private static BEncoder bEncoder; 
	private static TrackerProperties trackerProperties;
	
	public RequestHandler(){
		
		//JdbcDAO =  JdbcDAO.getDAO();
		//bEncoder = BEncoder.getEncoder();
		trackerProperties = TrackerProperties.getTrackerProperties();
	}
	
	public byte[] handleRequest(Socket s){
	
		try{
			//TrackerUtils trackerUtils = new TrackerUtils();
			
			Map mapa = TrackerHttpUtils.getRequestParameterMap(s);
			String action=(String)mapa.get("action");
			
			if (action.equals("announce")){
				return  doTrackerAnnounce(mapa);
			}	
			else if (action.equals("scrape")){
				return doTrackerScrape(mapa);
			}
			else if (action.equals("trackerupdate")){
				TrackerRefresher.updateTracker((byte[])mapa.get("modifiedPeers"));
				return "OK".getBytes("UTF-8");
			}
			return BEncoder.bencodeErrorMessage ("erro: escolha entre fazer um announce ou um scrape");
		} catch (Exception e){
		
			System.out.println("Erro processando request em handleRequest:");
			e.printStackTrace();
			return BEncoder.bencodeErrorMessage ("erro processando request no tracker");
		}
	}
 
	/****************************************************************************/
	/****************************************************************************/	
	
	public byte[]  doTrackerAnnounce(Map mapa) throws Exception{
	//public String doTrackerAnnounce(Map mapa) throws Exception{
		
		System.out.println("comecando a pegar properties do arquivo");
		
		if (trackerProperties.getProperty("tracker.PUBLIC_TRACKER").equals("false")){
			 if (mapa.get("pid")==null){
				return BEncoder.bencodeErrorMessage("erro: pid nao encontrado");
			 }	 
		}
		
		//se tiver uma key event no announce, trata ela aqui
		if ((mapa.get("event") != null) && (!mapa.get("event").equals(""))){
			
			String status = handleEventKey(mapa);
			if (!status.equals(OK))	{			
				return  BEncoder.bencodeErrorMessage(status);
			}	
		}
				
		/*pode ser que nao precise logar estatisticas de peers de trackers publicos*/
		if (trackerProperties.getProperty("tracker.PUBLIC_TRACKER").equals("true")){
			if ( trackerProperties.getProperty( "tracker.publictracker.LOG_USER_DOWNLOADS").equals("true")){
				System.out.println("fazendo o PRIMEIRO update do peer (tracker publico)");
				JdbcDAO.updatePeerDownloadStats(mapa);
			}
		}
		
		/*se nao eh tracker publico entao eh privado*/
		/*testando se precisa fazer atualizacao de ratio no tracker privado*/
		else if (trackerProperties.getProperty("tracker.ratio.RATIO_UPDATE").equals("onannounce")){
			System.out.println("fazendo o SEGUNDO update do peer (tracker privado)");
			JdbcDAO.updatePeerDownloadStats(mapa);
		}
		
		return  BEncoder.getBEncodedResponse(mapa);
	}
			
	/****************************************************************************/
	/****************************************************************************/			
			
	//public String doTrackerScrape(Map mapa) throws Exception{
	public byte[]  doTrackerScrape(Map mapa) throws Exception{

		//BEncoder bEncoder = BEncoder.getEncoder();
		return  BEncoder.bencodeScrapeResponse(mapa);
	}		
	
	/****************************************************************************/
	/****************************************************************************/			
	private String handleEventKey(Map mapa){		
	
		if (mapa.get("event").equals("started")){
			
			//Boolean activeRatio = Boolean.valueOf();		
			String status=OK; 		
			if (trackerProperties.getProperty("tracker.ratio.RATIO_SYSTEM_ACTIVE").equals("true")){
				status =checkUserRatio(mapa);
			}
			status = checkBannedClient(mapa);

			if (!status.equals(OK)){
				return status;
			}

			JdbcDAO.insertNewPeer(mapa);
			System.out.println("inserindo novo peer");
			return OK;

		} else if (mapa.get("event").equals("completed")){
			JdbcDAO.insertNewSeeder(mapa);
			return OK;

		} else if (mapa.get("event").equals("stopped")){
						
			//atualiza estatisticas do peer e remove ele da lista de peers
			JdbcDAO.updatePeerDownloadStats(mapa);
			
			if (trackerProperties.getProperty("tracker.ratio.RATIO_SYSTEM_ACTIVE").equals("true") && trackerProperties.getProperty("tracker.ratio.RATIO_SYSTEM_MODE").equals("pertorrent")){
				updateHitAndRuns(mapa);
			}
			
			//um tracker simples excluiria o peer usando o metodo abaixo
			//JdbcDAO.deletePeer(mapa);
			//mas um tracker distribuido nao pode deletar um peer sem avisar os otros trackers que o peer deu stop
			//entao marca o peer como parado e depois que avisar, deleta
			JdbcDAO.markPeerAsStopped(mapa);
			//return "torrent stopped";
			return OK;
		}
		return ("parametro desconhecido na key event:"+mapa.get("event"));
	}	
/****************************************************************************/
/****************************************************************************/			
	private String checkUserRatio(Map mapa){
					
			if (trackerProperties.getProperty("tracker.ratio.RATIO_SYSTEM_MODE").equals("global")){
				if ((JdbcDAO.getUserRatio(mapa)) < Double.parseDouble(trackerProperties.getProperty("tracker.ratio.MIN_RATIO"))) {
					if (JdbcDAO.getTorrentDownloaded(mapa)==false){
						return "download negado:ratio insuficiente";
					}
				}
			}
			else{
				int hitandruns = JdbcDAO.getHitAndRuns(mapa);
				if (hitandruns > Integer.parseInt( trackerProperties.getProperty("tracker.ratio.MAX_HIT_AND_RUNS"))){
					return "download negado:numero maximo de hit and runs atingido";
				}
			}
		
		return OK;
	}
	
	/****************************************************************************/
	/****************************************************************************/			

	private String checkBannedClient(Map mapa){
		
		String peer_id = (String)mapa.get("peer_id");
		String siglaClienteUsado= peer_id.substring(1,3);
		System.out.println("siglaClienteUsado="+siglaClienteUsado);
				
		String bannedClients = trackerProperties.getProperty("tracker.clients.BANNED_CLIENTS");
		
		if (bannedClients !=null){
			int index = bannedClients.indexOf(siglaClienteUsado);
			System.out.println("index"+index);
				
			if (index!=-1){
				int versionNumber = Integer.parseInt(peer_id.substring(3,7));
				System.out.println("versionNumber"+versionNumber);
					
				int bannedVersion= Integer.parseInt(bannedClients.substring(index+2, index+6));
				System.out.println("bannedVersion"+bannedVersion);
				if (versionNumber<=bannedVersion){
					return "download negado: cliente banido do tracker";
				}
			}
		}
		return OK;
	}
	
	/****************************************************************************/
	/****************************************************************************/			
			
	private void updateHitAndRuns(Map mapa){
	
		int down = JdbcDAO.getTrafficAmount(mapa, JdbcDAO.DOWNLOADED);
		int up = JdbcDAO.getTrafficAmount(mapa, JdbcDAO.UPLOADED);
		int min_up=Integer.parseInt(trackerProperties.getProperty("tracker.ratio.pertorrent.MIN_UP_TO_HIT_AND_RUN"));
		if ( up < (down * min_up) ){
			JdbcDAO.setTorrentAsHitAndRun(mapa, true);
		}
		else{  JdbcDAO.setTorrentAsHitAndRun(mapa,false); }
	}		
	
 }
 